package Algorithm;

import java.util.ArrayList;
import java.util.Collections;

import database.MovieLensDatabase;
import similarity.OtherSimilarity;
import type.Movie;
import type.Rating;
import type.User;

public class DemographicBased 
{

	public static double estimateRating2(User aUser, Movie aMovie)
	{
		//If the movie is already rated
		if(aUser.getRatingList().containsKey(aMovie))
		{
			return aUser.getRatingList().get(aMovie).getRating();
		}
		
		ArrayList<Neighbour> knn = new ArrayList<Neighbour>(); 
		for (User user : aMovie.getRatingList().keySet())
		{
			double similarity = OtherSimilarity.betweenDemographic(aUser, user);
			knn.add( new Neighbour(similarity, user.getRatingList().get(aMovie).getRating()) );
			
		}
		
		Collections.sort(knn);
		double max_vote = Double.NEGATIVE_INFINITY;
		int rating = 0;
		for(int r = 1; r <= 5; ++r)
		{
			double vote_ir = 0.0;
			for(int i = 0; i<knn.size() && i<50; ++i)
			{
				if(r == knn.get(i).rating)
				{
					vote_ir += knn.get(i).rating * knn.get(i).similarity;
				}
			}
			max_vote = Math.max(max_vote, vote_ir);
			if(max_vote == vote_ir)
				rating = r;
		}
		return rating;
	}
	
	static private class Neighbour implements Comparable<Neighbour>{
		public Double similarity;
		public Integer rating;
		
		public Neighbour(Double similarity, Integer rating){
			this.similarity = similarity;
			this.rating = rating;
		}

		@Override
		public int compareTo(Neighbour o) {
			return this.similarity.compareTo(o.similarity)*-1;
		}
	}
	
	public static double estimateRating(User aUser, Movie aMovie)
	{
		//If the movie is already rated
		if(aUser.getRatingList().containsKey(aMovie))
		{
			return aUser.getRatingList().get(aMovie).getRating();
		}
		
		double weightedRatingAccumulator = 0.0f;
		double absoluteSimilarityAccumulator = 0.0f;
		
		for (User user : aMovie.getRatingList().keySet())
		{
			double similarity = OtherSimilarity.betweenDemographic(aUser, user);
			weightedRatingAccumulator += user.getRatingList().get(aMovie).getRating() * similarity;
			absoluteSimilarityAccumulator += similarity;
		}
		
		//Could create a division by 0
		return absoluteSimilarityAccumulator == 0 ? aUser.getMeanRating() :
			weightedRatingAccumulator / absoluteSimilarityAccumulator;
	}
	
	public static void main(String[] args) {
		MovieLensDatabase db = new MovieLensDatabase("..\\..\\database\\ml-100k");
		
		double errorRateAverage = 0.0;
		for(int i=0; i<5; ++i){
			
			ArrayList<Rating> testRatings = db.selectRatingSet(i);
			double sqError = 0.0;
			for (Rating rating : testRatings) {
				double estimationResult = DemographicBased.estimateRating(rating.getUser(), rating.getMovie());
				sqError += Math.pow(estimationResult - rating.getRating(), 2.0);
			}
			double recommendationErrorRate = Math.sqrt(sqError / testRatings.size());
			System.out.println("Error rate for " + i + " is " + recommendationErrorRate);
			errorRateAverage += recommendationErrorRate;
		}
		errorRateAverage /= 5.0;
		System.out.println("Error rate : " + errorRateAverage);
	}
}
